package com.pan.annotation.aspect;

import com.pan.annotation.UpdateStatusCheck;
import com.pan.enume.EntityEnum;
import com.pan.enume.StatusLevel;
import com.pan.excep.enume.AspectErrorEnum;
import com.pan.excep.error.AspectException;
import com.pan.tools.ApplicationContextUtils;
import com.pan.tools.ArrayTools;
import com.pan.tools.RedisTools;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Aspect
@Component
public class UpdateStatusCheckAspect {


    @Resource
    private RedisTools redisTools;


    @Pointcut("@annotation(com.pan.annotation.UpdateStatusCheck)")
    public void annotationCut(){}

    public Method getTargetMethod(JoinPoint joinPoint) throws NoSuchMethodException {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Class[] parameterType = methodSignature.getParameterTypes();
        String methodName = methodSignature.getName();
        Method method = joinPoint.getTarget().getClass().getMethod(methodName,parameterType);
        return method;
    }

    @Before("annotationCut()")
    public void powerCheck(JoinPoint joinPoint) {
        Method targetMethod;
        try {
            targetMethod = getTargetMethod(joinPoint);
        } catch (NoSuchMethodException e) {
            throw new AspectException(500,"获取不到代理方法", UpdateStatusCheck.class,null);
        }
        UpdateStatusCheck powerCheck = targetMethod.getAnnotation(UpdateStatusCheck.class);
        String statusName = powerCheck.statusName();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        Integer statusIndex = ArrayTools.indexOf(parameterNames,statusName);
        if (statusIndex == null ){
            throw new AspectException(AspectErrorEnum.ASPECT_ANNOTATION_PARAMETER_ERROR.getCode(),
                    AspectErrorEnum.ASPECT_ANNOTATION_PARAMETER_ERROR.getMessage(),
                    UpdateStatusCheck.class,targetMethod);
        }
        Integer status = (Integer) args[statusIndex];
        EntityEnum entityEnum = powerCheck.entity();
        String identity;
        try {
            identity = new StatusLevel().get(entityEnum,status);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new AspectException(500,"修改的状态不存在",powerCheck.getClass(),targetMethod);
        }

        String ticketName = powerCheck.ticketName();
        Integer ticketIndex = ArrayTools.indexOf(args,ticketName);
        if (ticketIndex == null ){
            throw new AspectException(AspectErrorEnum.ASPECT_ANNOTATION_PARAMETER_ERROR.getCode(),
                    AspectErrorEnum.ASPECT_ANNOTATION_PARAMETER_ERROR.getMessage(),
                    UpdateStatusCheck.class,targetMethod);
        }
        String ticket = (String) args[ticketIndex];
        if (!redisTools.exists(identity+":"+ticket).getData()){
            throw new AspectException(403,"该用户身份无修改该状态的权限",powerCheck.getClass(),targetMethod);
        }
        Long id = (Long) redisTools.hget(identity+":"+ticket,"id").getData();
        if (identity.equals("user")){
            String idName = powerCheck.idName();
            Integer idIndex = ArrayTools.indexOf(parameterNames,idName);
            if (idIndex == null){
                throw new AspectException(500,"找不到entity的id参数",powerCheck.getClass(),targetMethod);
            }
            Long entityId = (Long) args[idIndex];
            Class selectDaoClass = entityEnum.getSelectDaoClass();
            Method selectMethod;
            try {
                selectMethod = selectDaoClass.getMethod("selectById",Long.class);
            } catch (NoSuchMethodException e) {
                throw new AspectException(500,"找不到selectById这个方法",powerCheck.getClass(),targetMethod);
            }
            Object dao = ApplicationContextUtils.getBean(selectDaoClass);
            Object selectResult;
            try {
                selectResult = selectMethod.invoke(dao,entityId);
            } catch (IllegalAccessException |InvocationTargetException e) {
                throw new AspectException(500,"调用selectById方法出错",powerCheck.getClass(),targetMethod);
            }
            Class entityType = entityEnum.getEntityType();
            Field userIdField;
            try {
                userIdField = entityType.getDeclaredField("userId");
            } catch (NoSuchFieldException e) {
                throw new AspectException(500,"该实体类型不存在userId属性",powerCheck.getClass(),targetMethod);
            }
            userIdField.setAccessible(true);
            Long userId;
            try {
                userId = (Long) userIdField.get(selectResult);
            } catch (IllegalAccessException e) {
                throw new AspectException(500,"该实体类型不存在userId属性",powerCheck.getClass(),targetMethod);
            }
            if (!userId.equals(id)){
                throw new AspectException(403,"该订单不属于该用户",powerCheck.getClass(),targetMethod);
            }
        }

    }

}
